home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Applications / Eudora 1.3.1 / source / buildtoc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-16  |  17.6 KB  |  761 lines  |  [TEXT/MPS ]

  1. #define FILE_NUM 45
  2. /* Copyright (c) 1991-1992 by the University of Illinois Board of Trustees */
  3. #pragma load EUDORA_LOAD
  4. #pragma segment BuildTOC
  5.  
  6.     void GleanFrom(UPtr line,MSumPtr sum);
  7.     long BeautifyDate(UPtr dateStr,long *zoneSecs);
  8.     short SalvageTOC(TOCHandle old, TOCHandle new);
  9.     void TrimWrap(UPtr str,int openC,int closeC);
  10.     long UnixDate2Secs(PStr date);
  11.     short MonthNum(CStr cp);
  12.  
  13. /************************************************************************
  14.  * RebuildTOC - rebuild a corrupt or out-of-date toc, salvaging what we
  15.  * can.
  16.  ************************************************************************/
  17. TOCHandle ReBuildTOC(long dirId,UPtr name)
  18. {
  19.     short refN=0,err;
  20.     long size;
  21.     Str63 tocName;
  22.     TOCHandle newTocH=nil;
  23.     short oldCount, newCount, salvCount;
  24.     
  25.     /*
  26.      * read the old one into memory
  27.      */
  28.     PCopy(tocName,name); PCat(tocName,"\p.toc");
  29.     if (err=FSHOpen(tocName,MyVRef,dirId,&refN,fsRdPerm) ||
  30.             (err=GetEOF(refN,&size)))
  31.     {
  32.         if (err!=fnfErr) FileSystemError(READ_TOC,tocName,err);
  33.     }
  34.     else
  35.     {
  36.         DamagedTOC = NuHandle(size);
  37.         if (!DamagedTOC) WarnUser(READ_TOC,MemError());
  38.         else
  39.         {
  40.             if (err=FSRead(refN,&size,LDRef(DamagedTOC)))
  41.                 FileSystemError(READ_TOC,tocName,err);
  42.         }
  43.         FSClose(refN);
  44.     }
  45.     if (err==fnfErr) err = noErr;
  46.     
  47.     if (!err || AlertStr(TOC_SALV_ALRT,Stop,name)==OK)
  48.     {
  49.         /*
  50.             * build the new one
  51.             */
  52.         if ((newTocH = BuildTOC(dirId,name)) && !err && DamagedTOC)
  53.         {
  54.             oldCount = (*DamagedTOC)->count;
  55.             newCount = (*newTocH)->count;
  56.             if (oldCount && newCount)
  57.             {
  58.                 Str255 s;
  59.                 salvCount = SalvageTOC(DamagedTOC,newTocH);         /* and salvage */
  60.                 ComposeRString(s,SALV_REPORT,salvCount,oldCount,newCount-salvCount);
  61.                 AlertStr(OK_ALRT,Note,s);
  62.             }
  63.         }
  64.     }
  65.     
  66.     if (DamagedTOC) ZapHandle(DamagedTOC);
  67.     return(newTocH);
  68. }
  69.  
  70. /************************************************************************
  71.  * SalvageTOC - reconcile and old a new TOC
  72.  ************************************************************************/
  73. short SalvageTOC(TOCHandle old, TOCHandle new)
  74. {
  75.     short first,last,mid;
  76.     MSumPtr oldSum;
  77.     long offset;
  78.     short salvaged=0;
  79.     
  80.     LDRef(old); LDRef(new);
  81.     (*old)->count = (GetHandleSize(old)-(sizeof(TOCType)-sizeof(MSumType)))/
  82.                                     sizeof(MSumType);
  83.     
  84.     for (oldSum=(*old)->sums;oldSum<(*old)->sums+(*old)->count;oldSum++)
  85.     {
  86.         offset = oldSum->offset;
  87.         first = 0; last=(*new)->count-1;
  88.         for (mid=(first+last)/2;first<=last;mid=(first+last)/2)
  89.             if (offset<(*new)->sums[mid].offset)
  90.                 last = mid -1;
  91.             else if (offset==(*new)->sums[mid].offset)
  92.                 break;
  93.             else
  94.                 first = mid+1;
  95.         if (first<=last && (*new)->sums[mid].length==oldSum->length)
  96.         {
  97.             salvaged++;
  98.             (*new)->sums[mid] = *oldSum;
  99.         }
  100.     }
  101.     
  102.     UL(old); UL(new);
  103.     CleanseTOC(new);
  104.     return(salvaged);
  105. }
  106.  
  107. /**********************************************************************
  108.  * BuildTOC - build a table of contents for a file.  The TOC is built
  109.  * in memory.  This gets a little hairy in spots because the routine is
  110.  * used both for received messages and messages under composition; but
  111.  * the complication does not substantially affect the flow of the
  112.  * function, so I let it stand.
  113.  **********************************************************************/
  114. TOCHandle BuildTOC(long dirId,UPtr name)
  115. {
  116.     TOCHandle tocH=nil;
  117.     MSumType sum;
  118.     int err;
  119.     Boolean isOut;
  120.     Str255 scratch;
  121.     
  122.     /*
  123.      * first, try opening the file
  124.      */
  125.     if (err=OpenLine(MyVRef,dirId,name))
  126.     {
  127.         FileSystemError(OPEN_MBOX,name,err);
  128.         return(nil);
  129.     }
  130.     
  131.     if ((tocH=NewZHandle(sizeof(TOCType)))==nil)
  132.     {
  133.         WarnUser(READ_MBOX,MemError());
  134.         goto failure;
  135.     }
  136.     
  137.     /*
  138.      * figure out for once and for all if we are an in or an out box
  139.      */
  140.     isOut = False;
  141.     if (dirId==MyDirId)
  142.     {
  143.         GetRString(scratch,IN);
  144.         if (EqualString(scratch,name,False,True))
  145.             (*tocH)->which = IN;
  146.         else
  147.         {
  148.             GetRString(scratch,OUT);
  149.             if (EqualString(scratch,name,False,True))
  150.             {
  151.                 (*tocH)->which = OUT;
  152.                 isOut = True;
  153.             }
  154.             else
  155.             {
  156.                 GetRString(scratch,TRASH);
  157.                 if (EqualString(scratch,name,False,True))
  158.                     (*tocH)->which = TRASH;
  159.             }
  160.         }
  161.     }
  162.     
  163.     ReadSum(nil,False);
  164.     while (ReadSum(&sum,isOut))
  165.     {
  166.         if (!SaveMessageSum(&sum,tocH))
  167.         {
  168.             WarnUser(SAVE_SUM,MemError());
  169.             goto failure;
  170.         }
  171.     }
  172.     ReadSum(nil,False);
  173.  
  174.     /*
  175.      * success
  176.      */
  177.     CloseLine();
  178.     (*tocH)->refN = 0;
  179.     (*tocH)->vRef = MyVRef;
  180.     (*tocH)->dirId = dirId;
  181.     BlockMove(name,(*tocH)->name,*name+1L);
  182.     (*tocH)->version = 0;
  183.     (*tocH)->dirty = True;
  184.     SetHandleBig(tocH,sizeof(TOCType) + 
  185.         ((*tocH)->count ? (*tocH)->count-1 : 0)*sizeof(MSumType));
  186.     return (tocH);
  187.  
  188. failure:
  189.     if (tocH != nil) DisposHandle(tocH);
  190.     CloseLine();
  191.     return(nil);
  192. }
  193.  
  194.  /************************************************************************
  195.  * ReadSum - read a summary, from the current position in the lineio
  196.  * routines.
  197.  ************************************************************************/
  198. Boolean ReadSum(MSumPtr sum,Boolean isOut)
  199.     static int type;
  200.     Str255 line;
  201.     static UHandle oldLine=nil;
  202.     enum {BEGIN, IN_BODY, IN_HEADER} state;
  203.     Str63 duck;
  204.     long secs;
  205.     Str31 prior;
  206.     Boolean lookPrior;
  207.     long origZone;
  208.     
  209.     if (!sum)
  210.     {
  211.         if (oldLine)
  212.         {
  213.             DisposHandle(oldLine);
  214.             oldLine = nil;
  215.         }
  216.         return(True);
  217.     }
  218.     
  219.     /*
  220.      * set up the priority stuff
  221.      */
  222.     if (lookPrior = !PrefIsSet(PREF_NO_IN_PRIOR)) GetRString(prior,HEADER_STRN+PRIORITY_HEAD);
  223.  
  224.     /*
  225.      * now, read from it line by line
  226.      * break messages when sendmail-style From line is found
  227.      */
  228.     state = BEGIN;
  229.     WriteZero(sum,sizeof(MSumType));
  230.     sum->state = UNREAD;
  231.     sum->tableId = DEFAULT_TABLE;
  232.     while (oldLine || (type=GetLine(line,sizeof(line))))
  233.     {
  234.         if (oldLine)
  235.         {
  236.             BlockMove(*oldLine,line,sizeof(line));
  237.             DisposHandle(oldLine);
  238.             oldLine = nil;
  239.         }
  240.         switch(type)
  241.         {
  242.             case LINE_START:
  243.                 if (IsFromLine(line))
  244.                 {
  245.                     if (state!=BEGIN)
  246.                     {
  247.                         if ((oldLine=NuHandle(sizeof(line)))==nil)
  248.                         {
  249.                             WarnUser(MEM_ERR,MemError());
  250.                             return(False);
  251.                         }
  252.                         BlockMove(line,*oldLine,sizeof(line));
  253.                         return(True);
  254.                     }
  255.                     WriteZero(sum,sizeof(MSumType));
  256.                     sum->tableId = DEFAULT_TABLE;
  257.                     if (!isOut) GleanFrom(line,sum);
  258.                     sum->offset = TellLine();
  259.                     sum->state = isOut ? UNSENDABLE : UNREAD;
  260.                     state = IN_HEADER;
  261.                 }
  262.                 else if (state==IN_HEADER)
  263.                 {                                             /* look for date, subj, from lines */
  264.                     if (*line=='\n')
  265.                     {
  266.                         state = IN_BODY;
  267.                         sum->bodyOffset = TellLine()-sum->offset;
  268.                     }
  269.                     else if (!striscmp(line,"date:"))
  270.                     {
  271.                         CopyHeaderLine(duck,sizeof(duck),line);
  272.                         if (secs=BeautifyDate(duck,&origZone)) PtrTimeStamp(sum,secs,origZone);
  273.                         else
  274.                         {
  275.                             if (*duck > sizeof(sum->date)-2) *duck=sizeof(sum->date)-2;
  276.                             BlockMove(duck,sum->date,sizeof(sum->date));
  277.                         }
  278.                     }
  279.                     else if (!isOut && !striscmp(line,"from:"))
  280.                     {
  281.                         CopyHeaderLine(sum->from,sizeof(sum->from),line);
  282.                         BeautifyFrom(sum->from);
  283.                     }
  284.                     else if (isOut && !striscmp(line,"to:"))
  285.                     {
  286.                         CopyHeaderLine(sum->from,sizeof(sum->from),line);
  287.                         if (*sum->from) sum->state = SENDABLE;
  288.                     }
  289.                     else if (!striscmp(line,"subject:"))
  290.                     {
  291.                         CopyHeaderLine(sum->subj,sizeof(sum->subj),line);
  292.                     }
  293.                     else if (!striscmp(line,"status: r"))
  294.                         sum->state=READ;
  295.                     else if (lookPrior && !striscmp(line,prior+1))
  296.                         sum->priority = sum->origPriority = Display2Prior(atoi(line+*prior));
  297.                 }
  298.                 break;
  299.             case LINE_MIDDLE:
  300.                 break;
  301.             default:
  302.                 state=BEGIN;
  303.                 goto done;                     /* error message already given */
  304.                 break;
  305.         }
  306.         sum->length += strlen(line);
  307.         if (state==BEGIN) state=IN_HEADER;
  308.     }
  309. done:
  310.     return(state!=BEGIN);
  311. }
  312.  
  313. /**********************************************************************
  314.  * BeautifySum - beautify a message summary before saving it.  This
  315.  * involves beautifying the from address and the date.
  316.  **********************************************************************/
  317. void BeautifySum(MSumPtr sum)
  318. {
  319.     if (sum->seconds) PtrTimeStamp(sum,sum->seconds,ZoneSecs());
  320.     BeautifyFrom(sum->from);
  321. }
  322.  
  323. /**********************************************************************
  324.  * IsFromLine - determine whether or not a given line is a sendmail From
  325.  * line.
  326.  **********************************************************************/
  327. Boolean IsFromLine(UPtr line)
  328. {
  329.     int num,len;
  330.     int quote=0;
  331.     Str255 scratch;
  332.     UPtr cp;
  333.     short weekDay,year,tym,day,month,other,remote,from;
  334.  
  335. #define isdig(c) ('0'<=(c) && (c)<='9') 
  336.     if (line[0]!='F' || line[1]!='r' || line[2]!='o' || line[3]!='m')
  337.         return (False);  /* quick and dirty */
  338.     
  339.     /*
  340.      * it passed the first test.    Now, we have to be more rigorous.
  341.      * this is a sample sendmail From line:
  342.      * >From paul@uxc.cso.uiuc.edu Wed Jun 14 12:36:18 1989<
  343.      * However, various systems do various bad things with the From line.
  344.      * therefore, I've changed it to look for:
  345.      */
  346.     
  347.     /* check for the space after the from */
  348.     line += 4;
  349.     if (*line++!=' ') return (False);
  350.     
  351.     /* skip the return address */
  352.     while (*line && (quote || *line!=' '))
  353.     {
  354.         if (*line=='"') quote = !quote;
  355.         line++;
  356.     }
  357.     if (!*line++) return (False);
  358.     while (*line==' ') line++;
  359.     
  360.     remote=from=weekDay=day=from=year=tym=month=other=0;
  361.     len = strlen(line);
  362.     if (len>sizeof(scratch)-1) return(False);
  363.     strcpy(scratch,line);
  364.     for (cp=strtok(scratch," \t\n,");cp;cp=strtok(nil," \t\n,"))
  365.     {
  366.         len = strlen(cp);
  367.         num = atoi(cp);
  368.         if (num<24 && (len>=5 && cp[2]==':') && (len==5 || len==8 && cp[5]==':'))
  369.         {
  370.             if (tym++) return(False);
  371.         }
  372.         else if (!year && day && len==2 && isdig(cp[len-1]))
  373.         {
  374.             if (year++) return(False);
  375.         }
  376.         else if (len<=2 && num && num<32)
  377.         {
  378.             if (day++) return(False);
  379.         }
  380.         else if (len==4&&num>1900)
  381.         {
  382.             if (year++) return(False);
  383.         }
  384.         else if (len==6 && !striscmp(cp,"remote"))
  385.         {
  386.             if (remote++ || from) return(False);
  387.         }
  388.         else if (len==4 && !striscmp(cp,"from"))
  389.         {
  390.             if (!remote || from++) return(False);
  391.         }
  392.         else if (len==3 &&
  393.             !(striscmp(cp,"mon") && striscmp(cp,"tue") && striscmp(cp,"wed")
  394.              && striscmp(cp,"thu") && striscmp(cp,"fri")
  395.              && striscmp(cp,"sat") && striscmp(cp,"sun")))
  396.         {
  397.             if (weekDay++) return(False);
  398.         }
  399.         else if (len==3 && !(striscmp(cp,"jan") && striscmp(cp,"feb") &&
  400.             striscmp(cp,"mar") && striscmp(cp,"apr") &&
  401.             striscmp(cp,"may") && striscmp(cp,"jun") &&
  402.             striscmp(cp,"jul") && striscmp(cp,"aug") &&
  403.             striscmp(cp,"sep") && striscmp(cp,"oct") &&
  404.             striscmp(cp,"nov") && striscmp(cp,"dec")))
  405.         {
  406.             if (month++) return(False);
  407.         }
  408.         else
  409.         {
  410.             other++;
  411.         }
  412.     }
  413.     return (day && year && month && tym && other<=2);
  414. }
  415. /**********************************************************************
  416.  * GleanFrom - grab relevant info from sendmail From line
  417.  * input line is in C format, fields in summary are in Pascal form
  418.  **********************************************************************/
  419. void GleanFrom(UPtr line,MSumPtr sum)
  420. {
  421.     Str255 copy;
  422.     register char *cp=copy;
  423.     register char *ep;
  424.     long seconds;
  425.     long offset = ZoneSecs();
  426.     
  427.     strcpy(copy,line);
  428.     /*
  429.      * from address
  430.      */
  431.     while (*cp++ != ' ');
  432.     for (ep=cp; *ep!= ' '; ep++);
  433.     *ep = '\0';
  434.     MakePStr(sum->from,cp,ep-cp);
  435.     
  436.     /*
  437.      * date
  438.      */
  439.     for (cp=++ep;*ep!='\n' && *ep; ep++);
  440.     *ep = '\0';
  441.     MakePStr(sum->date,cp,ep-cp);
  442.     
  443.     /*
  444.      * TimeStamp
  445.      */
  446.     seconds = UnixDate2Secs(sum->date)-offset;
  447.     PtrTimeStamp(sum,seconds,offset);
  448. }
  449.  
  450.  
  451. /************************************************************************
  452.  * UnixDate2Secs - convert a UNIX date into seconds
  453.  ************************************************************************/
  454. long UnixDate2Secs(PStr date)
  455. {
  456.     Str63 copy;
  457.     UPtr end;
  458.     DateTimeRec dtr;
  459.     long secs = 0;
  460.     
  461.     PCopy(copy,date);
  462.     end = copy+*copy;
  463.     /* let's null-terminate this, shall we? */
  464.     end[1] = 0;
  465.     
  466.     /* back up and grab the year */
  467.     while (*end!=' ' && end>copy) end--;
  468.     dtr.year = atoi(end);
  469.     if (dtr.year>0 && dtr.year<1900) dtr.year+=1900;
  470.     
  471.     /* seconds */
  472.     *end = 0;
  473.     while (*end!=':'&&end>copy) end--;
  474.     dtr.second = atoi(end+1);
  475.     
  476.     /* minutes */
  477.     *end = 0;
  478.     while (*end!=':'&&end>copy) end--;
  479.     dtr.minute = atoi(end+1);
  480.     
  481.     /* hours */
  482.     *end = 0;
  483.     while (*end!=' '&&end>copy) end--;
  484.     dtr.hour = atoi(end+1);
  485.     
  486.     /* date */
  487.     *end = 0;
  488.     while (*end!=' '&&end>copy) end--;
  489.     dtr.day = atoi(end+1);
  490.  
  491.     /* Month */
  492.     *end = 0;
  493.     while (*--end==' ' && end>=copy);
  494.     while (*end!=' '&&end>copy) end--;
  495.     dtr.month = MonthNum(end+1);
  496.     
  497.     if (dtr.year && dtr.month) Date2Secs(&dtr,&secs);
  498.     return(secs);
  499. }
  500.  
  501. /************************************************************************
  502.  * MonthNum - get the month number from a month name
  503.  ************************************************************************/
  504. short MonthNum(CStr cp)
  505. {
  506.     char monthStr[4];
  507.     short month=0;
  508.     
  509.     /*
  510.      * copy and lowercase
  511.      */
  512.     BlockMove(cp,monthStr,3);
  513.     monthStr[3] = 0;
  514.     for (cp=monthStr;*cp;cp++) if (isupper(*cp)) *cp = tolower(*cp);
  515.     cp = monthStr;
  516.     
  517.     switch(cp[0])
  518.     {
  519.         case 'j': month = cp[1]=='a' ? 1 : (cp[2]=='n' ? 6 : 7); break;
  520.         case 'f': month = 2; break;
  521.         case 'm': month = cp[2]=='r' ? 3 : 5; break;
  522.         case 'a': month = cp[1]=='p' ? 4 : 8; break;
  523.         case 's': month = 9; break;
  524.         case 'o': month = 10; break;
  525.         case 'n': month = 11; break;
  526.         case 'd': month = 12; break;
  527.     }
  528.     return(month);
  529. }
  530.  
  531. /************************************************************************
  532.  * BeautifyDate - make a date look better
  533.  * assumes the date is in smtp date format
  534.  ************************************************************************/
  535. long BeautifyDate(UPtr dateStr,long *origZone)
  536. {
  537.     UPtr cp, cp2;
  538.     DateTimeRec dtr;
  539.     long secs;
  540.     long offset;
  541.     *origZone = 0;
  542.     
  543.     if (*dateStr < 10) return(0);  /* ignore really short dates */
  544.     dateStr[*dateStr+1] = 0;
  545.     WriteZero(&dtr,sizeof(dtr));
  546.     
  547.     /*
  548.      * delete day of the week
  549.      */
  550.     if (cp=strchr(dateStr+1,','))
  551.     {
  552.         for (cp++;isspace(*cp);cp++);
  553.         strcpy(dateStr+1,cp);
  554.         *dateStr = strlen(dateStr+1);
  555.     }
  556.     
  557.     /*
  558.      * make sure that single-digit dates begin with a space, not a '0' and
  559.      * not nothing
  560.      */
  561.     dtr.day = atoi(dateStr+1);
  562.     if (dateStr[1]=='0')
  563.         dateStr[1] = ' ';
  564.     else if (dateStr[2]==' ')
  565.     {
  566.         Str255 temp;
  567.         *temp = 1;
  568.         PCat(temp,dateStr);
  569.         PCopy(dateStr,temp);
  570.         dateStr[1] = ' ';
  571.     }
  572.         
  573.     /*
  574.      * delete year, if present
  575.      */
  576.     /* pointing at day */
  577.     for (cp=dateStr+2;*cp && !isspace(*cp);cp++);
  578.     for (;isspace(*cp);cp++);
  579.     /* pointing at month */
  580.     dtr.month = MonthNum(cp);
  581.     for (;*cp && !isspace(*cp);cp++);
  582.     for (cp2=cp;isspace(*cp2);cp2++);
  583.     
  584.     if (*cp && isdigit(*cp2))
  585.     {
  586.         dtr.year = atoi(cp2);
  587.         if (dtr.year<20) dtr.year += 2000;
  588.         else if (dtr.year<1900) dtr.year += 1900;
  589.         while (isdigit(*cp2)) cp2++;
  590.         strcpy(cp,cp2);
  591.         *dateStr -= cp2-cp;
  592.         dateStr[*dateStr+1] = 0;
  593.     }
  594.     
  595.     /*
  596.      * delete the seconds, if present
  597.      */
  598.     dtr.hour = atoi(cp);
  599.     if (cp=strchr(cp,':'))
  600.     {
  601.         dtr.minute = atoi(cp+1);
  602.         if (cp[3]==':')
  603.         {
  604.             dtr.second = atoi(cp+4);
  605.             strcpy(cp+3,cp+6);
  606.             *dateStr -= 3;
  607.             dateStr[*dateStr+1] = 0;
  608.         }
  609.     }
  610.     
  611.     if (dtr.year)
  612.     {
  613.         Date2Secs(&dtr,&secs);
  614.         cp = strchr(dateStr+1,':');
  615.         cp2 = dateStr+*dateStr+1;
  616.         if (cp&&cp+4<cp2)
  617.         {
  618.             cp+=4;
  619.             if (offset = atoi(cp))
  620.             {
  621.                 if (*cp == '-') offset *= -1;
  622.                 offset = (3600 * offset)/100 + 60*(offset%100);
  623.                 if (*cp == '-') offset *= -1;
  624.             }
  625.             else
  626.             {
  627.                 offset = TZName2Offset(cp);
  628.             }
  629.         }
  630.         else
  631.             offset = ZoneSecs();
  632.         secs -= offset;
  633.         *origZone = offset;
  634.     }
  635.     else secs = 0;
  636.     return(secs);
  637. }
  638.  
  639. /************************************************************************
  640.  * BeautifyFrom - make a from line look better
  641.  ************************************************************************/
  642. void BeautifyFrom(UPtr fromStr)
  643. {
  644.     UPtr cp1,cp2;
  645.     int len;
  646.     
  647.     fromStr[*fromStr+1] = 0;
  648.     
  649.     /*
  650.      * elide <>'ed text, unless it's all there is
  651.      */
  652.     TrimWhite(fromStr);
  653.     if (cp1=strchr(fromStr+1,'<'))
  654.     {
  655.         if (cp2=strchr(cp1+1,'>'))
  656.         {
  657.             while (cp2[1]==' ') cp2++;
  658.             len = cp2 - cp1 - 1;
  659.             if (len>0 && len < *fromStr-2)
  660.             {
  661.                 strcpy(cp1,cp2+1);
  662.                 *fromStr -= len+2;
  663.             }
  664.         }
  665.     }
  666.     /*
  667.      * prefer parenthesized text
  668.      */
  669.     else if (cp1=strchr(fromStr+1,'('))
  670.         if (cp2=strchr(cp1+1,')'))
  671.         {
  672.             len = cp2 - cp1 - 1;
  673.             if (len>0)
  674.             {
  675.                 *fromStr = len;
  676.                 strncpy(fromStr+1,cp1+1,len);
  677.                 fromStr[*fromStr+1] = 0;
  678.             }
  679.         }
  680.     TrimWhite(fromStr);
  681.     TrimWrap(fromStr,'(',')');
  682.     TrimWrap(fromStr,'"','"');
  683. }
  684.  
  685. void TrimWrap(UPtr str,int openC,int closeC)
  686. {
  687.   if (*str>1 && str[1] == openC && str[*str] == closeC)
  688.     {
  689.       BlockMove(str+2,str+1,*str-2);
  690.         *str -= 2;
  691.         str[*str+1] = 0;
  692.     }
  693. }
  694.     
  695. /************************************************************************
  696.  * SumToFrom - build a sendmail-style from line from a message summary
  697.  ************************************************************************/
  698. int SumToFrom(MSumPtr sum, UPtr fromLine)
  699. {
  700.     char *start, *end;
  701.     Str31 delims;
  702.     Str63 fromWhom;
  703.     short n;
  704.     
  705.     GetRString(delims,DELIMITERS);
  706.     if (sum && Tokenize(sum->from+1,*sum->from,&start,&end,delims))
  707.     {
  708.         strncpy(fromWhom+1,start,end-start);
  709.         *fromWhom = end-start;
  710.     }
  711.     else
  712.         GetRString(fromWhom,UNKNOWN_SENDER);
  713.  
  714.     PCopy(fromLine,"\pFrom ");
  715.     PCat(fromLine,fromWhom);
  716.     n = fromLine[0]+1;
  717.     LocalDateTimeStr(fromLine+n);
  718.     fromLine[0] += fromLine[n]+1;
  719.     fromLine[n] = ' ';
  720.     p2cstr(fromLine);
  721.     return(strlen(fromLine));
  722. }
  723.  
  724. /**********************************************************************
  725.  * CopyHeaderLine - copy the contents of a header line (C format)
  726.  * into a Pascal string.
  727.  **********************************************************************/
  728. void CopyHeaderLine(UPtr to,int size,UPtr from)
  729. {
  730.     while (*from++ != ':');
  731.     for (from++; *from == ' '; from++);
  732.     strncpy(to,from,size-2);
  733.     to[size-2] = 0;
  734.     c2pstr(to);
  735.     TrimWhite(to);
  736.  
  737. /************************************************************************
  738.  * FindTOCSpot - find a spot in a file that's big enough to hold a
  739.  * message.
  740.  ************************************************************************/
  741. long FindTOCSpot(TOCHandle tocH, long length)
  742. {
  743. #pragma unused(length)
  744.     long end=0;
  745.     MSumPtr sum;
  746.     MSumPtr limit;
  747.     
  748.     /*
  749.      * for now, just return the end
  750.      */
  751.     sum = (*tocH)->sums;
  752.     limit = sum + (*tocH)->count;
  753.     for (; sum<limit ; sum++)
  754.         if (end < sum->offset+sum->length)
  755.             end = sum->offset + sum->length;
  756.     
  757.     return(end);
  758. }
  759.